﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;

namespace GameLogic.Logic
{
    /// <summary>
    /// This Action will move the element according to Mouse movement.
    /// </summary>
    public class FollowMouseBehavior : Behavior<FrameworkElement>
    {
        public enum PositionOptions
        {
            None,
            X,
            Y,
            XY
        };

        // Private Properties
        private double maxX, maxY;
        private double minX, minY;
        
        private double width = 0;
        private double height = 0;
        private double oX = 0;
        private double oY = 0;

        // Vectors for Position and Velocity
        private Vector2D mousePosition = new Vector2D();
        private Vector2D targetPosition = new Vector2D();
        private Vector2D velocity = new Vector2D(0, 0);
        private Point center;

        private UIElement parent;

        #region Dependency Properties

        public static readonly DependencyProperty FollowPositionProperty = DependencyProperty.Register("FollowPosition", typeof(PositionOptions), typeof(FollowMouseBehavior), null);
        public static readonly DependencyProperty MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(FollowMouseBehavior), null);

        [Category("Mouse Properties")]
        public PositionOptions FollowPosition
        {
            get { return (PositionOptions)this.GetValue(FollowPositionProperty); }
            set { this.SetValue(FollowPositionProperty, value); }
        }

        [Category("Mouse Properties")]
        public Thickness Margin
        {
            get { return (Thickness)this.GetValue(MarginProperty); }
            set { this.SetValue(MarginProperty, value); }
        }

        #endregion

        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.Loaded += this.OnAssociatedObjectLoaded;
        }

        private void OnAssociatedObjectLoaded(object sender, RoutedEventArgs e)
        {
            this.parent = VisualTreeHelper.GetParent(this.AssociatedObject) as UIElement;
            this.center = new Point(this.AssociatedObject.ActualWidth / 2, this.AssociatedObject.ActualHeight / 2);

            // Calculate Max/Min
            FrameworkElement container = parent as FrameworkElement;
            this.maxX = container.ActualWidth - this.AssociatedObject.ActualWidth - this.Margin.Right;
            this.minX = 0 + this.Margin.Left;
            this.maxY = container.ActualHeight - this.AssociatedObject.ActualHeight - this.Margin.Bottom;
            this.minY = 0 + this.Margin.Top;

            this.oX = this.AssociatedObject.RenderTransformOrigin.X;
            this.oY = this.AssociatedObject.RenderTransformOrigin.Y;
            this.width = this.AssociatedObject.Width;
            this.height = this.AssociatedObject.Height;

            this.targetPosition.X = Canvas.GetLeft(this.AssociatedObject) + (this.width * this.oX);
            this.targetPosition.Y = Canvas.GetTop(this.AssociatedObject) + (this.height * this.oX);

            container.MouseMove += this.HandleMouseMove;
        }

        private void HandleMouseMove(object sender, MouseEventArgs e)
        {
            UIElement reference = sender as UIElement;
            Point mouse = e.GetPosition(reference);

            double newX = mouse.X - (width * oX) - this.center.X;
            double newY = mouse.Y - (height * oY) - this.center.Y;

            newX = Math.Min(Math.Max(newX, this.minX), this.maxX);
            newY = Math.Min(Math.Max(newY, this.minY), this.maxY);

            if (this.FollowPosition != PositionOptions.None)
            {
                switch (this.FollowPosition)
                {
                    case PositionOptions.X:
                        Canvas.SetLeft(this.AssociatedObject, newX);
                        break;
                    case PositionOptions.Y:
                        Canvas.SetTop(this.AssociatedObject, newY);
                        break;
                    case PositionOptions.XY:
                        Canvas.SetLeft(this.AssociatedObject, newX);
                        Canvas.SetTop(this.AssociatedObject, newY);
                        break;
                }
            }
        }
    }
}

//// TODO: Not working any more, due to GameContainer redesign
//using System;
//using System.ComponentModel;
//using System.Windows;
//using System.Windows.Input;

//namespace GameLogic.Logic
//{
//    public class FollowMouseBehavior : GameContainerBehavior<FrameworkElement>
//    {
//        #region Dependency properties
//        [Category("FollowMouse Properties")]
//        public PositionOptions FollowPosition
//        {
//            get { return (PositionOptions)this.GetValue(FollowPositionProperty); }
//            set { this.SetValue(FollowPositionProperty, value); }
//        }
//        public static readonly DependencyProperty FollowPositionProperty =
//          DependencyProperty.Register(
//              "FollowPosition",
//              typeof(PositionOptions),
//              typeof(FollowMouseBehavior),
//              new PropertyMetadata(PositionOptions.XY, null));

//        public enum PositionOptions
//        {
//            None,
//            X,
//            Y,
//            XY
//        };
//        #endregion

//        bool followMouse;
//        Point center;
//        Rect startPosition;
//        Rect worldLimit;

//        protected override void OnAttached()
//        {
//            base.OnAttached();

//        }

//        protected override void OnGameContainerInitialized()
//        {
//            base.OnGameContainerInitialized();

//            this.center = new Point(this.AssociatedObject.ActualWidth / 2, this.AssociatedObject.ActualHeight / 2);

//            UIElement root = this.GameContainer as UIElement;
//            Point position = this.AssociatedObject.TransformToVisual(root).Transform(new Point(0, 0));
//            this.startPosition = new Rect(
//                position.X - this.center.X,
//                position.Y - this.center.Y,
//                this.AssociatedObject.ActualWidth,
//                this.AssociatedObject.ActualHeight);

//            Vector2D gcv = new Vector2D(this.GameContainer.GameControl.ActualWidth, this.GameContainer.GameControl.ActualHeight);
//            double gcvo = gcv.Length / 2;

//            Vector2D gv = new Vector2D(this.GameContainer.ActualWidth, this.GameContainer.ActualHeight);
//            double gvo = gcv.Length / 2;

//            this.worldLimit = new Rect(
//                gcvo - gvo,
//                gcvo - gvo,
//                this.GameContainer.GameControl.ActualWidth - this.AssociatedObject.ActualWidth,
//                this.GameContainer.GameControl.ActualHeight - this.AssociatedObject.ActualHeight);

//            this.GameContainer.GameControl.MouseEnter += new MouseEventHandler(OnMouseEnter);
//            this.GameContainer.GameControl.MouseLeave += new MouseEventHandler(OnMouseLeave);
//            this.GameContainer.GameControl.MouseMove += new MouseEventHandler(OnMouseMove);
//        }

//        private void OnMouseEnter(object sender, MouseEventArgs e)
//        {
//            followMouse = true;
//        }

//        private void OnMouseLeave(object sender, MouseEventArgs e)
//        {
//            followMouse = false;
//        }

//        private void OnMouseMove(object sender, MouseEventArgs e)
//        {
//            if (followMouse && this.FollowPosition != PositionOptions.None)
//            {
//                UIElement root = this.GameContainer as UIElement;
//                Point mousePos = e.GetPosition(this.GameContainer.GameControl);
//                Point targetPos = new Point(0, 0);

//                switch (this.FollowPosition)
//                {
//                    case PositionOptions.X:
//                        targetPos.X = mousePos.X - this.center.X;
//                        break;

//                    case PositionOptions.Y:
//                        targetPos.Y = mousePos.Y - this.center.Y;
//                        break;

//                    case PositionOptions.XY:
//                        targetPos.X = mousePos.X - this.center.X;
//                        targetPos.Y = mousePos.Y - this.center.Y;
//                        break;
//                }

//                if (targetPos.X < worldLimit.X)
//                    targetPos.X = worldLimit.X;

//                if (targetPos.X > worldLimit.Width)
//                    targetPos.X = worldLimit.Width;

//                if (targetPos.Y < worldLimit.Y)
//                    targetPos.Y = worldLimit.Y;

//                if (targetPos.Y > worldLimit.Height)
//                    targetPos.Y = worldLimit.Height;

//                Rect newPos = new Rect(
//                targetPos.X,
//                targetPos.Y,
//                this.AssociatedObject.ActualWidth,
//                this.AssociatedObject.Height);
//                this.AssociatedObject.Arrange(newPos);
//            }
//        }

//        private void OnGameContainer_Reset(object sender, EventArgs e)
//        {
//            this.AssociatedObject.Arrange(this.startPosition);
//        }
//    }
//}
